package org.carl.base.driving.core;

import cn.hutool.core.util.StrUtil;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import lombok.extern.slf4j.Slf4j;
import org.carl.base.driving.annotation.ReceiveConfiguration;
import org.carl.base.driving.annotation.ReceiveMethod;
import org.carl.base.driving.bean.DrivingBeanConfig;
import org.carl.base.driving.entity.ReceiveMessage;
import org.carl.base.driving.enums.ReceiveHandleStateEnum;
import org.carl.base.driving.service.receive.ReceiveHandle;
import org.carl.base.driving.service.receive.ReceiveMessageService;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.Advised;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 接收执行类
 * @author 陈青松
 */
@Slf4j
@Service
@ConditionalOnBean(value ={DrivingBeanConfig.class})
public class ReceiveExecute {

    @Autowired
    private ReceiveMessageService receiveMessageService;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private LockTemplate lockTemplate;

    /**
     * 接收处理类
     */
    private volatile Map<String, ReceiveHandle> handleMap;

    /**
     * 处理锁名称
     */
    private static final String RECEIVE_EXECUTE_LOCK = "RECEIVE:EXECUTE:LOCK:";

    /**
     * 初始化 - 继承方式
     *
     * @return
     */
    private synchronized Map<String, ReceiveHandle> initHandleMapByClass() {
        // 获取所有实现类型
        Map<String, ReceiveHandle> beans = applicationContext.getBeansOfType(ReceiveHandle.class);
        if (CollectionUtils.isEmpty(beans)) {
            return Collections.emptyMap();
        }
        return beans.values().stream().collect(Collectors.toMap(ReceiveHandle::getName, x -> x));
    }

    /**
     * 初始化 - 注解方式
     *
     * @return
     */
    private synchronized Map<String, ReceiveHandle> initHandleMapByAnnotation() {
        Map<String, ReceiveHandle> annotationHandleMap = new HashMap<>();
        // 获取所有实现类型
        Map<String, Object> objectMap = applicationContext.getBeansWithAnnotation(ReceiveConfiguration.class);
        if (CollectionUtils.isEmpty(objectMap)) {
            return annotationHandleMap;
        }
        // 解析方法
        for (Object object : objectMap.values()) {
            Method[] methods = null;
            if (object instanceof Advised) {
                Advised advised = (Advised) object;
                TargetSource targetSource = advised.getTargetSource();
                try {
                    if (targetSource == null || targetSource.getTargetClass() == null) {
                        continue;
                    }
                    methods = targetSource.getTargetClass().getMethods();
                } catch (Exception e) {
                    log.error("代理类异常", e);
                }
            } else {
                methods = object.getClass().getMethods();
            }
            if (methods == null || methods.length == 0) {
                continue;
            }
            // 获取实现
            for (Method method : methods) {
                ReceiveMethod receiveMethod = method.getAnnotation(ReceiveMethod.class);
                if (receiveMethod == null) {
                    continue;
                }
                annotationHandleMap.put(receiveMethod.name(), new ReceiveHandle() {
                    @Override
                    public String getName() {
                        return receiveMethod.name();
                    }

                    @Override
                    public void execute(String data) {
                        try {
                            // 执行对应方法
                            method.invoke(object, data);
                        } catch (IllegalAccessException | InvocationTargetException e) {
                            log.error("异常", e);
                            try {
                                throw e;
                            } catch (Exception ex) {
                                ex.printStackTrace();
                            }
                        }
                    }
                });
            }
        }
        return annotationHandleMap;
    }

    /**
     * 通过类型获取接收处理类
     *
     * @param handleName
     * @return
     */
    public ReceiveHandle getReceiveHandle(String handleName) {
        if (CollectionUtils.isEmpty(handleMap)) {
            synchronized (this) {
                if (CollectionUtils.isEmpty(handleMap)) {
                    handleMap = new HashMap<>();
                    Map<String, ReceiveHandle> classHandleMap = initHandleMapByClass();
                    if (!CollectionUtils.isEmpty(classHandleMap)) {
                        handleMap.putAll(classHandleMap);
                    }
                    Map<String, ReceiveHandle> annotationHandleMap = initHandleMapByAnnotation();
                    if (!CollectionUtils.isEmpty(annotationHandleMap)) {
                        handleMap.putAll(annotationHandleMap);
                    }
                }
            }
        }
        return handleMap.get(handleName);
    }

    /**
     * 业务处理操作
     *
     * @param receiveId
     * @param handleName
     */
    @Transactional(rollbackFor = Exception.class)
    public void execute(String receiveId, String handleName) {
        log.debug("消息驱动开始业务处理:{} handleName:{}", receiveId, handleName);
        // 验证参数
        if (StrUtil.isEmpty(receiveId) || StrUtil.isEmpty(handleName)) {
            return;
        }

        // 开始调用处理
        ReceiveHandle receiveHandle = getReceiveHandle(handleName);
        log.debug("消息驱动开始业务处理,获取业务Handle:{}", receiveHandle);
        if (receiveHandle == null) {
            return;
        }
        // 获取锁
        final LockInfo lockInfo = lockTemplate.lock(RECEIVE_EXECUTE_LOCK+ StrUtil.COLON+receiveId, 3000L,5000L);
        if (null == lockInfo) {
            throw new RuntimeException("业务处理中,请稍后再试");
        }
        // 获取锁成功，处理业务
        try {
            // 必须是待处理状态
            ReceiveMessage receiveMessageSelect = receiveMessageService.selectById(receiveId);
            if (receiveMessageSelect == null || StringUtils.isEmpty(receiveMessageSelect.getData())) {
                throw new RuntimeException("消息异常消息id:" + receiveId);
            }
            log.info("消息驱动业务处理:{}当前状态:{}", receiveMessageSelect.getReceiveId(), receiveMessageSelect.getHandleState());
            // 定时任务会查初始状态数据并调用此方执行
            if (!ReceiveHandleStateEnum.INIT.getCode().equals(receiveMessageSelect.getHandleState())) {
                return;
            }
            // 修改消息处理中
            receiveMessageService.updateHandleState(receiveMessageSelect.getReceiveId(), ReceiveHandleStateEnum.PROCESSING.getCode());
            log.debug("驱动开始业务处理,参数{}", receiveMessageSelect);

            // 处理业务（业务处理和修改消息状态必须在一个事务中）
            receiveHandle.execute(receiveMessageSelect.getData());

            log.debug("驱动结束业务处理,参数{}", receiveMessageSelect);
            // 修改消息处理成功
            receiveMessageService.updateHandleState(receiveMessageSelect.getReceiveId(), ReceiveHandleStateEnum.PROCESS_SUCCESS.getCode());
        } finally {
            //释放锁
            lockTemplate.releaseLock(lockInfo);
        }
        log.debug("消息驱动结束业务处理");
    }

}
